{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "dfe37963-1af6-44fc-a841-8e462443f5e6",
   "metadata": {},
   "source": [
    "# Welcome to RAG week!!\n",
    "\n",
    "## Expert Knowledge Worker\n",
    "\n",
    "### A question answering Assistant that is an expert knowledge worker\n",
    "### To be used by employees of Insurellm, an Insurance Tech company\n",
    "### The AI assistant needs to be accurate and the solution should be low cost.\n",
    "\n",
    "This project will use RAG (Retrieval Augmented Generation) to ensure our question/answering assistant has high accuracy.\n",
    "\n",
    "This first implementation will use a simplistic, brute-force type of RAG..\n",
    "\n",
    "<table style=\"margin: 0; text-align: left;\">\n",
    "    <tr>\n",
    "        <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
    "            <img src=\"../assets/business.jpg\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
    "        </td>\n",
    "        <td>\n",
    "            <h2 style=\"color:#181;\">Business applications of this week's projects</h2>\n",
    "            <span style=\"color:#181;\">RAG is perhaps the most immediately applicable technique of anything that we cover in the course! In fact, there are commercial products that do precisely what we build this week: nuanced querying across large databases of information, such as company contracts or product specs. RAG gives you a quick-to-market, low cost mechanism for adapting an LLM to your business area.</span>\n",
    "        </td>\n",
    "    </tr>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ba2779af-84ef-4227-9e9e-6eaf0df87e77",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import glob\n",
    "from dotenv import load_dotenv\n",
    "from pathlib import Path\n",
    "import gradio as gr\n",
    "from openai import OpenAI"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "810359e6",
   "metadata": {},
   "source": [
    "<table style=\"margin: 0; text-align: left;\">\n",
    "    <tr>\n",
    "        <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
    "            <img src=\"../assets/important.jpg\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
    "        </td>\n",
    "        <td>\n",
    "            <h1 style=\"color:#900;\">Important Note</h1>\n",
    "            <span style=\"color:#900;\">\n",
    "            This lab, and all the labs for Week 5, has been updated to use LangChain 1.0. This is intended to be reviewed with the new video series as of November 2025. If you're reviewing the older video series, then please consider doing <code>git checkout original</code> to revert to the prior code, then later <code>git checkout main</code> to get back to the new code. I have a really exciting week ahead, with evals and Advanced RAG!\n",
    "            </span>\n",
    "        </td>\n",
    "    </tr>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9258e738",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Setting up\n",
    "\n",
    "load_dotenv(override=True)\n",
    "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
    "if openai_api_key:\n",
    "    print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"OpenAI API Key not set\")\n",
    "\n",
    "MODEL = \"gpt-4.1-nano\"\n",
    "openai = OpenAI()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3db802f8",
   "metadata": {},
   "source": [
    "### Let's read in all employee data into a dictionary"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9e0652c2-3d76-40c7-8313-9dc1895155a8",
   "metadata": {},
   "outputs": [],
   "source": [
    "knowledge = {}\n",
    "\n",
    "filenames = glob.glob(\"knowledge-base/employees/*\")\n",
    "\n",
    "for filename in filenames:\n",
    "    name = Path(filename).stem.split(' ')[-1]\n",
    "    with open(filename, \"r\", encoding=\"utf-8\") as f:\n",
    "        knowledge[name.lower()] = f.read()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c9932835",
   "metadata": {},
   "outputs": [],
   "source": [
    "knowledge"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2c85a11b-b04d-4066-b243-f96139ca106f",
   "metadata": {},
   "outputs": [],
   "source": [
    "knowledge[\"lancaster\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a1d231f9-091e-4c72-b0f8-6af578a74e22",
   "metadata": {},
   "outputs": [],
   "source": [
    "filenames = glob.glob(\"knowledge-base/products/*\")\n",
    "\n",
    "for filename in filenames:\n",
    "    name = Path(filename).stem\n",
    "    with open(filename, \"r\", encoding=\"utf-8\") as f:\n",
    "        knowledge[name.lower()] = f.read()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aba46a57-d973-4195-8fe3-70fc60687192",
   "metadata": {},
   "outputs": [],
   "source": [
    "knowledge.keys()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "129c7d1e-0094-4479-9459-f9360b95f244",
   "metadata": {},
   "outputs": [],
   "source": [
    "SYSTEM_PREFIX = \"\"\"\n",
    "You represent Insurellm, the Insurance Tech company.\n",
    "You are an expert in answering questions about Insurellm; its employees and its products.\n",
    "You are provided with additional context that might be relevant to the user's question.\n",
    "Give brief, accurate answers. If you don't know the answer, say so.\n",
    "\n",
    "Relevant context:\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d40e390b-c110-42d5-8d80-daf3295b9862",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_relevant_context_simple(message):\n",
    "    text = ''.join(ch for ch in message if ch.isalpha() or ch.isspace())\n",
    "    words = text.lower().split()\n",
    "    relevant_context = []\n",
    "    for word in words:\n",
    "        if word in knowledge:\n",
    "            relevant_context.append(knowledge[word])\n",
    "    return relevant_context          "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2f9fd049",
   "metadata": {},
   "source": [
    "## But a more pythonic way:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c94ea125",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_relevant_context(message):\n",
    "    text = ''.join(ch for ch in message if ch.isalpha() or ch.isspace())\n",
    "    words = text.lower().split()\n",
    "    return [knowledge[word] for word in words if word in knowledge]   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d126cfcb-e85c-4dd9-837e-9d2b8436d4b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "get_relevant_context(\"Who is lancaster?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d94c768d-c47a-4c34-85e9-7b786da96507",
   "metadata": {},
   "outputs": [],
   "source": [
    "get_relevant_context(\"Who is Lancaster and what is carllm?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5a7cef7f-f214-4bac-8217-3f9ab9ba1bf0",
   "metadata": {},
   "outputs": [],
   "source": [
    "def additional_context(message):\n",
    "    relevant_context = get_relevant_context(message)\n",
    "    if not relevant_context:\n",
    "        result = \"There is no additional context relevant to the user's question.\"\n",
    "    else:\n",
    "        result = \"The following additional context might be relevant in answering the user's question:\\n\\n\"\n",
    "        result += \"\\n\\n\".join(relevant_context)\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2b36399c-440b-4049-9d39-68d208283c71",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(additional_context(\"Who is Alex Lancaster?\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "968e7bf2-e862-4679-a11f-6c1efb6ec8ca",
   "metadata": {},
   "outputs": [],
   "source": [
    "def chat(message, history):\n",
    "    system_message = SYSTEM_PREFIX + additional_context(message)\n",
    "    messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
    "    response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
    "    return response.choices[0].message.content"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bbbcb659-13ce-47ab-8a5e-01b930494964",
   "metadata": {},
   "source": [
    "## Now we will bring this up in Gradio using the Chat interface -\n",
    "\n",
    "A quick and easy way to prototype a chat with an LLM"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c3536590-85c7-4155-bd87-ae78a1467670",
   "metadata": {},
   "outputs": [],
   "source": [
    "view = gr.ChatInterface(chat, type=\"messages\").launch(inbrowser=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6d2ba45a",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
